package com.hitqz.robot.biz.autoInit;
import java.time.LocalDateTime;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hitqz.robot.api.business.dto.SentinelModeRecordDto;
import com.hitqz.robot.api.business.enums.EquipmentEnum;
import com.hitqz.robot.api.business.enums.RobotDriverEnum;
import com.hitqz.robot.api.business.enums.WorkStatusEnum;
import com.hitqz.robot.api.business.model.dto.FlowPatrolTicketsDto;
import com.hitqz.robot.api.common.entity.*;
import com.hitqz.robot.api.dispatch.protocol.ProtocolEnum;
import com.hitqz.robot.biz.core.FileProperties;
import com.hitqz.robot.biz.service.*;
import com.hitqz.robot.biz.util.PatrolConstant;
import com.hitqz.robot.camera.EquipmentFactory;
import com.hitqz.robot.camera.IEquipmentService;
import com.hitqz.robot.camera.configure.EquipmentCmdEnum;
import com.hitqz.robot.camera.dto.EquipmentParamsDto;
import com.hitqz.robot.camera.dto.MediaFileDto;
import com.hitqz.robot.camera.dto.QueryParamsDto;
import com.hitqz.robot.camera.dto.TakePicParamsDto;
import com.hitqz.robot.driver.model.IRobotPosDto;
import com.hitqz.robot.driver.parent.RobotDriverService;
import com.hitqz.robot.netty.service.Send2ServerService;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@Slf4j
@AllArgsConstructor
public class SentinelModeService {

    private static List<PatrolPoseGroup> poseGroup;
    private static RobotConfig config;

    final private  RobotDriverService robotDriverService;

    final private RobotService robotService;

    final private PatrolPoseGroupService patrolPoseGroupService;

    final private PatrolPoseService patrolPoseService;

    final private RobotEquipmentService robotEquipmentService;

    final private EquipmentFactory equipmentFactory;

    final private FileProperties fileProperties;

    final private PatrolCheckTypeService patrolCheckTypeService;

    final private ServerProperties serverProperties;
    final private RobotConfigService robotConfigService;
    final private Send2ServerService send2ServerService;

    final private AtomicInteger seq = new AtomicInteger(0);


    @PostConstruct
    public void init() {
        // sentinelMode.txt 每行写一个位置姿态组的名称
        String filePath = System.getProperty("user.dir") + File.separator + "sentinelMode.txt";
        File file = new File(filePath);
        if (!file.exists()){
            log.info("未找到哨兵模式启动文件");
            return;
        }
        List<String> poseGroupName = FileUtil.readLines(file, "utf-8");
        if (poseGroupName == null || poseGroupName.isEmpty()){
            log.info("未找到哨兵模式文件无内容");
            return;
        }
        poseGroup = patrolPoseGroupService.list(Wrappers.<PatrolPoseGroup>lambdaQuery().in(PatrolPoseGroup::getName, poseGroupName));
        config = robotConfigService.getOneEnable();
        if (poseGroup == null || poseGroup.isEmpty()){
            log.info("未找到哨兵模式位置姿态组");
            return;
        }
        RobotDriverEnum driverVersion = robotDriverService.getDriverVersion();
        if (!Objects.equals(driverVersion, RobotDriverEnum.TRACK)){
            log.info("哨兵模式只支持TRACK控制器");
            return;
        }
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(this::doCheck,  60 * 3, 20, TimeUnit.SECONDS);
        log.info("3分钟后开启哨兵模式");
    }

    public void doCheck() {
        try{
            //哨兵模式开关
            boolean b = PatrolConstant.sentinelModeEnable.get();
            if (!b){
                log.info("sentinel mode disable");
                return;
            }
            //确定位置
            IRobotPosDto webPos = robotDriverService.getWebPos();
            if (webPos == null || !webPos.isReached() || Math.abs(webPos.getX())>100){
                log.debug("不在坞站，不启动哨兵模式");
                return;
            }
            //确定空闲状态
            Robot robot = robotService.getDefaultRobot();
            if (!Objects.equals(robot.getWorkStatus(), WorkStatusEnum.FREE.getCode())){
                log.debug("当前状态不是空闲，不启动哨兵模式");
            }
            for (PatrolPoseGroup patrolPoseGroup : poseGroup) {
                List<PatrolPose> list = patrolPoseService.list(Wrappers.<PatrolPose>lambdaQuery().eq(PatrolPose::getGroupId, patrolPoseGroup.getId()));
                //转动云台
                for (PatrolPose pose : CollUtil.emptyIfNull(list)) {
                    RobotEquipment equipment = robotEquipmentService.getById(pose.getEquipmentId());
                    IEquipmentService service = equipmentFactory.getServiceByBrand(equipment.getBrand());
                    if (service==null){
                        continue;
                    }
                    List<EquipmentParamsDto> paramsDtos = JSONArray.parseArray(pose.getJson(), EquipmentParamsDto.class);
                    QueryParamsDto queryParamsDto = new QueryParamsDto();
                    queryParamsDto.setPassword(equipment.getPassword());
                    queryParamsDto.setUsername(equipment.getUsername());
                    queryParamsDto.setPort(equipment.getPort());
                    queryParamsDto.setChannel(equipment.getChannel());
                    queryParamsDto.setIp(equipment.getIp());
                    service.setEquipmentParams(queryParamsDto, paramsDtos , false);
                }
                MediaFileDto mediaFileDto = this.takePic();
                if (mediaFileDto==null){
                    continue;
                }
                JSONObject detect = this.detect(mediaFileDto);
                if (detect==null){
                    continue;
                }
                File file = new File(mediaFileDto.getAbsolutePath());
                if (file.exists()){
                    log.info("删除原图:{},{}",file.delete(),mediaFileDto.getAbsolutePath());;
                }
                String visionPicUrl = this.getVisionPicUrl(detect);
                if (StrUtil.isBlank(visionPicUrl)){
                    log.info("no person");
                    continue;
                }

                SentinelModeRecordDto dto = new SentinelModeRecordDto();
                dto.setTitle("人员入侵");
                dto.setTime(new Date());
                dto.setRobotSn(robot.getRobotSn());
                dto.setRobotName(robot.getRobotName());
                dto.setUrl(config.getProcessManagerUri() + "/file" + visionPicUrl);
                //上报
                send2ServerService.send2ServerData((int) ProtocolEnum.SENTINEL_MODE_RECORD.getCmd(), JSONObject.toJSONString(dto));
            }
        } catch (Exception e) {
            log.error("哨兵模式错误",e);
        }
    }


    private MediaFileDto takePic(){
        RobotEquipment camera = robotEquipmentService.getOne(Wrappers.<RobotEquipment>lambdaQuery()
                .eq(RobotEquipment::getIsDetect, 1)
                .eq(RobotEquipment::getType, EquipmentEnum.VISIBLE_LIGHT_CHANNEL.getType())
                .last("limit 1"));
        if (camera == null) {
            return  null;
        }
        IEquipmentService service = equipmentFactory.getServiceByBrand(camera.getBrand());
        TakePicParamsDto paramsDto = new TakePicParamsDto();
        paramsDto.setBasePath(fileProperties.getLocal().getBasePath());
        paramsDto.setFolder("sentinel");
        QueryParamsDto queryParamsDto = new QueryParamsDto();
        queryParamsDto.setPassword(camera.getPassword());
        queryParamsDto.setUsername(camera.getUsername());
        queryParamsDto.setPort(camera.getPort());
        queryParamsDto.setChannel(camera.getChannel());
        queryParamsDto.setIp(camera.getIp());
        MediaFileDto mediaFileDto = (MediaFileDto) service.executeCmd(queryParamsDto, true, EquipmentCmdEnum.TAKE_PIC,paramsDto);
        log.info("拍照结果 {}", mediaFileDto);
        return mediaFileDto;
    }


    private JSONObject detect(MediaFileDto mediaFileDto){
        PatrolCheckType checkType = patrolCheckTypeService.getOne(Wrappers.<PatrolCheckType>lambdaQuery().like(PatrolCheckType::getName, "%人员%").last("limit 1"));
        if (checkType==null){
            return null;
        }
        //视觉项
        String visionUrl = checkType.getVisionUrl();
        String type = checkType.getVisionType();
        Robot robot = robotService.getDefaultRobot();
        String externalIp = StrUtil.isBlank(robot.getExternalIp()) ? "127.0.0.1" : robot.getExternalIp();
        String externalHost = StrUtil.isBlank(robot.getExternalPort()) ? externalIp + ":" + serverProperties.getPort() : externalIp + ":" + robot.getExternalPort();
        String host = (visionUrl.contains("127.0.0.1") || visionUrl.contains("localhost")) ? "127.0.0.1:"+ serverProperties.getPort() : externalHost;
        // 编码，避免#等特殊符号
        String url = "http://"+ host + "/file/" + mediaFileDto.getRelativePath();
        HashMap<String, Object> query = new HashMap<>();
        query.put("url",url);
        query.put("rectype",Integer.parseInt(type));
        log.info("视觉地址：{},参数:{}",visionUrl,JSONObject.toJSONString(query));
        String result = "";
        try{
            result = HttpUtil.post(visionUrl, JSONObject.toJSONString(query), 15000);
        }catch (Exception e){
            log.info("视觉检测失败",e);
            return null;
        }
        log.info("视觉检测结果: {}", result);
        return JSONObject.parseObject(result);
    }

    private String getVisionPicUrl(JSONObject jsonObject){
        Integer code = jsonObject.getInteger("code");
        if (!Objects.equals(code,200)){
            return null;
        }
        String result = jsonObject.getString("result");
        if (!Objects.equals(result, "1")){
            return null;
        }
        String path = jsonObject.getString("path");
        if (StrUtil.isBlank(path)){
            return null;
        }
        return downloadImage(path);
    }

    private String downloadImage(String imageUrl) {
        InputStream in = null;
        int seqInt = seq.getAndIncrement();
        if (seqInt>20){
            seq.set(0);
        }
        String relativePath =  File.separator + "sentinel" + File.separator + seqInt + ".jpg";
        String path = fileProperties.getLocal().getBasePath() + relativePath;
        File file = new File(path);
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        try  {  // 打开输入流
            URL url = new URL(imageUrl.replace("/./","/"));  // 创建 URL 对象
            in = url.openStream();
            FileUtil.writeFromStream(in,path);
            return relativePath;
        } catch (IOException e) {
            log.error("down vision picture error:{}",e.getMessage());
            return "";
        } finally {
            try {
                if (in!=null) {
                    in.close();
                }
            } catch (IOException e) {
                log.error("InputStream close error:{}",e.getMessage());
            }
        }
    }


}
